from pynput import mouse
import tkinter as tk
from tkinter import Canvas, NW
from PIL import Image, ImageTk, ImageDraw
import threading
import time

# 创建主窗口，全屏且透明
root = tk.Tk()
root.title("Mouse Trail")
root.attributes("-fullscreen", True)
root.attributes("-alpha", 0.01)  # 设置窗口透明度（0.0全透明到1.0不透明）

# 创建Canvas，与窗口大小相同
canvas = Canvas(root, width=root.winfo_screenwidth(), height=root.winfo_screenheight(), bg='white')
canvas.pack(fill=tk.BOTH, expand=tk.YES)

# 变量来存储绘制状态、上一个点、轨迹图像和退出标志
drawing = False
last_point = None
canvas_image = Image.new("RGBA", (canvas.winfo_width(), canvas.winfo_height()), (255, 255, 255, 0))
exit_flag = threading.Event()  # 使用Event对象来同步线程

# 鼠标事件回调函数
def on_move(x, y):
    global last_point, drawing, canvas_image, exit_flag
    if exit_flag.is_set():
        return  # 如果设置了退出标志，则忽略鼠标事件
    if drawing:
        # 鼠标移动时绘制轨迹
        if last_point:
            draw_line(last_point, (x, y))
        last_point = (x, y)

def on_click(x, y, button, pressed):
    global drawing, last_point, exit_flag
    if exit_flag.is_set():
        return  # 如果设置了退出标志，则忽略鼠标事件
    if button == mouse.Button.left:
        # 鼠标左键按下时开始绘制，松开时停止绘制并启动轨迹逐渐消失
        drawing = pressed
        if not pressed and last_point:
            fade_trail()
            last_point = None  # 重置上一个点，避免松开后继续绘制
    elif button == mouse.Button.right:
        # 鼠标右键按下时退出全屏窗口
        exit_fullscreen()

# 绘制线条函数（考虑半透明效果）
def draw_line(p1, p2):
    global canvas_image
    draw = ImageDraw.Draw(canvas_image)
    draw.line([p1, p2], fill=(128, 0, 128, 128), width=2)  # 紫色，半透明
    update_canvas()

# 更新Canvas显示
def update_canvas():
    global canvas_image, canvas
    canvas_tk_image = ImageTk.PhotoImage(canvas_image)
    canvas.create_image(0, 0, anchor=NW, image=canvas_tk_image)
    canvas.tk_image = canvas_tk_image  # 保持对图像的引用，防止被垃圾回收

# 轨迹逐渐消失函数（同步执行）
def fade_trail():
    global canvas_image, canvas, exit_flag
    if canvas_image is None:
        return

    # 创建一个线程来处理轨迹逐渐消失，避免阻塞主线程
    def fade(image):
        # 这里使用局部变量 image 代替全局变量 canvas_image
        fade_image = image.copy()
        draw = ImageDraw.Draw(fade_image)

        # 降低整个图像的透明度来实现逐渐消失效果
        for alpha in range(255, 0, -5):  # 以5为步长降低透明度
            if exit_flag.is_set():
                break  # 如果设置了退出标志，则停止淡化
            for x in range(image.width):
                for y in range(image.height):
                    r, g, b, a = image.getpixel((x, y))
                    new_alpha = int(a * (alpha / 255))
                    fade_image.putpixel((x, y), (r, g, b, new_alpha))
            # 更新轨迹图像（这里需要注意，由于我们在局部变量中修改了图像，需要将其返回）
            # 但是在这个例子中，我们不直接更新全局变量，而是让 fade_trail 来处理
            # 因此，这里不更新 canvas_image，而是在 fade_trail 中处理返回值
            # 更新Canvas显示（同样，这里应该由 fade_trail 来处理）
            # 但是为了演示目的，我们暂时不在这里更新Canvas
            # 等待一段时间再进行下一次淡化
            time.sleep(0.05)

        # 淡化完成后，返回新的图像（在这个例子中不使用返回值）
        # return fade_image

    # 启动线程并传递 canvas_image 作为参数
    threading.Thread(target=fade, args=(canvas_image,), daemon=True).start()
    # 注意：由于我们在 fade 函数中没有更新全局变量，因此这里的 canvas_image 不会被修改
    # 如果需要修改全局变量，应该在 fade 函数中返回新的图像，并在 fade_trail 中更新全局变量
    # 但是这样做可能会导致线程安全问题，因为多个线程可能会同时尝试更新全局变量
    # 一个更好的方法是使用线程安全的队列或其他同步机制来传递数据


# 退出全屏窗口函数
def exit_fullscreen():
    global exit_flag
    exit_flag.set()  # 设置退出标志
